﻿/**************************************************************
 *
 * 唯一标识：0723f66b-f1e9-461b-b724-ff4f9a25daf4
 * 命名空间：Sgr.Utilities
 * 创建时间：2023/7/24 9:31:24
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：枚举操作工具类
 *
 **************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace Sgr.Utilities
{
    /// <summary>
    /// 枚举工具类
    /// </summary>
    public static class EnumHelper
    {
        /// <summary>
        /// 字符串转枚举
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <param name="value">要转换的字符串值</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns>转换后的枚举值</returns>
        /// <exception cref="ArgumentException">当转换失败时抛出</exception>
        public static TEnum StringToEnum<TEnum>(string value, bool ignoreCase = true) where TEnum : struct, Enum
        {
            Check.NotNull(value, nameof(value));

            if (Enum.TryParse<TEnum>(value, ignoreCase, out TEnum result))
                return result;

            throw new ArgumentException($"无法将字符串 '{value}' 转换为枚举类型 {typeof(TEnum).Name}");
        }

        /// <summary>
        /// 尝试将字符串转换为枚举
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <param name="value">要转换的字符串值</param>
        /// <param name="result">转换结果</param>
        /// <param name="ignoreCase">是否忽略大小写</param>
        /// <returns>是否转换成功</returns>
        public static bool TryStringToEnum<TEnum>(string value, out TEnum result, bool ignoreCase = true) where TEnum : struct, Enum
        {
            if (string.IsNullOrEmpty(value))
            {
                result = default;
                return false;
            }

            return Enum.TryParse(value, ignoreCase, out result);
        }

        /// <summary>
        /// 获取枚举的名称值对列表
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <returns>名称值对列表</returns>
        public static IEnumerable<NameValue> EnumToNameValues<TEnum>() where TEnum : struct, Enum
        {
            Type enumType = typeof(TEnum);
            return Enum.GetNames(enumType)
                .Select(name =>
                {
                    var field = enumType.GetField(name);
                    var value = Enum.Parse<TEnum>(name).ToString();
                    var description = field?.GetCustomAttribute<DescriptionAttribute>()?.Description ?? name;
                    return new NameValue(description, value);
                })
                .ToList();
        }

        /// <summary>
        /// 获取枚举值的描述
        /// </summary>
        /// <param name="value">枚举值</param>
        /// <returns>描述文本，如果没有Description特性则返回枚举名称</returns>
        public static string GetDescription(Enum value)
        {
            Check.NotNull(value, nameof(value));

            var field = value.GetType().GetField(value.ToString());
            if (field == null) return value.ToString();

            var attribute = field.GetCustomAttribute<DescriptionAttribute>();
            return attribute?.Description ?? value.ToString();
        }

        /// <summary>
        /// 获取枚举的所有值
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <returns>枚举值列表</returns>
        public static IEnumerable<TEnum> GetValues<TEnum>() where TEnum : struct, Enum
        {
            return Enum.GetValues<TEnum>();
        }

        /// <summary>
        /// 判断给定的值是否定义在枚举中
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <param name="value">要检查的值</param>
        /// <returns>是否是有效的枚举值</returns>
        public static bool IsDefined<TEnum>(object? value) where TEnum : struct, Enum
        {
            if (value == null) return false;
            return Enum.IsDefined(typeof(TEnum), value);
        }

        /// <summary>
        /// 获取枚举值的数值
        /// </summary>
        /// <param name="value">枚举值</param>
        /// <returns>对应的数值</returns>
        public static int GetNumericValue(Enum value)
        {
            Check.NotNull(value, nameof(value));
            return Convert.ToInt32(value);
        }
    }
}